1 /*
2  * Collie - An asynchronous event-driven network framework using Dlang development
3  *
4  * Copyright (C) 2015-2017  Shanghai Putao Technology Co., Ltd 
5  *
6  * Developer: putao's Dlang team
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11  
12 module collie.bootstrap.serversslconfig;
13 
14 import std.string;
15 
16 //import kiss.net;
17 
18 version(USE_SSL)
19 {
20     public import deimos.openssl.ssl;
21 	public import deimos.openssl.bio;
22 }
23 else
24 {
25     alias SSL_CTX = int;
26 }
27 
28 enum SSLMode
29 {
30     SSLv2v3 = 3,
31     TLSv1 = 4,
32     TLSv1_1 = 5,
33     TLSv1_2 = 6
34 }
35 
36 class ServerSSLConfig
37 {
38     this(SSLMode mode)
39     {
40         _mode = mode;
41     }
42 
43     SSL_CTX* generateSSLCtx()
44     {
45 		if(_ctx)
46 			return _ctx;
47 		version(USE_SSL)
48         {
49             final switch (_mode)
50             {
51             case SSLMode.SSLv2v3:
52 					_ctx = SSL_CTX_new(SSLv23_method());
53                 break;
54             case SSLMode.TLSv1:
55 					_ctx = SSL_CTX_new(TLSv1_method());
56                 break;
57             case SSLMode.TLSv1_1:
58 					_ctx = SSL_CTX_new(TLSv1_1_method());
59                 break;
60             case SSLMode.TLSv1_2:
61 					_ctx = SSL_CTX_new(TLSv1_2_method());
62                 break;
63             }
64 			if (_ctx is null)
65                 return null;
66 			if (SSL_CTX_use_certificate_file(_ctx, toStringz(_certificateFile), SSL_FILETYPE_PEM) < 0)
67             {
68                 error("SSL_CTX_use_certificate_file failed ! file : ", _certificateFile);
69 				SSL_CTX_free(_ctx);
70                 return null;
71             }
72 			if (SSL_CTX_use_PrivateKey_file(_ctx, toStringz(_privateKeyFile), SSL_FILETYPE_PEM) < 0)
73             {
74                 error("SSL_CTX_use_PrivateKey_file failed! file : ", _privateKeyFile);
75 				SSL_CTX_free(_ctx);
76                 return null;
77             }
78 			if (SSL_CTX_check_private_key(_ctx) < 0)
79             {
80                 error("SSL_CTX_check_private_key failed");
81 				SSL_CTX_free(_ctx);
82                 return null;
83             }
84         }
85         return _ctx;
86     }
87 
88     @property certificateFile(string file)
89     {
90         _certificateFile = file;
91     }
92 
93     @property certificateFile()
94     {
95         return _certificateFile;
96     }
97 
98     @property privateKeyFile(string file)
99     {
100         _privateKeyFile = file;
101     }
102 
103     @property privateKeyFile()
104     {
105         return _privateKeyFile;
106     }
107 
108     @property cipherList(string cliper)
109     {
110         _cipherList = cliper;
111     }
112 
113     @property cipherList()
114     {
115         return _cipherList;
116     }
117 
118     @property sslMode()
119     {
120         return _mode;
121     }
122 
123 private:
124     string _certificateFile;
125     string _privateKeyFile;
126     string _cipherList;
127     SSLMode _mode;
128 	SSL_CTX* _ctx = null;
129 }
130 
131 version(USE_SSL)
132 {
133     import core.sync.mutex;
134     import core.thread;
135 
136     shared static this()
137     {
138         SSL_load_error_strings();
139         SSL_library_init();
140         sslmutex = new Mutex[CRYPTO_num_locks()];
141         for (uint i = 0; i < sslmutex.length; ++i)
142         {
143             sslmutex[i] = new Mutex();
144         }
145         static if (OPENSSL_VERSION_NUMBER > 0x10000000L)
146         {
147             CRYPTO_THREADID_set_callback(&threadid_function);
148         }
149         else
150         {
151             CRYPTO_set_id_callback(&id_function);
152         }
153         CRYPTO_set_locking_callback(&ssl_lock_callback);
154     }
155 
156     shared static ~this()
157     {
158         static if (OPENSSL_VERSION_NUMBER > 0x10000000L)
159         {
160             CRYPTO_THREADID_set_callback(null);
161         }
162         else
163         {
164             CRYPTO_set_id_callback(null);
165         }
166         CRYPTO_set_locking_callback(null);
167     }
168 
169 private:
170     __gshared Mutex[] sslmutex;
171 
172 extern (C):
173     pragma(inline, true) ulong id_function()
174     {
175         return cast(ulong)(Thread.getThis.id);
176     }
177 
178     void threadid_function(CRYPTO_THREADID* id)
179     {
180         version (Windows)
181         {
182             CRYPTO_THREADID_set_numeric(id, cast(uint) id_function());
183         }
184         else
185         {
186             CRYPTO_THREADID_set_numeric(id, id_function());
187         }
188     }
189 
190     void ssl_lock_callback(int mode, int type, const(char)* file, int line)
191     {
192         if (mode & CRYPTO_LOCK)
193         {
194             sslmutex[type].lock();
195         }
196         else
197         {
198             sslmutex[type].unlock();
199         }
200     }
201 }